import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image
import os
import sys

class ImageConverterApp:
    def __init__(self, root):
        self.root = root
        self.root.title("图片转WebP/AVIF转换器")
        
        # 设置窗口图标
        self.set_window_icon()
        
        # 设置初始窗口大小
        self.set_initial_window_size()
        
        # 设置现代化深色主题样式
        self.setup_modern_theme()
        
        # 添加输出格式变量
        self.output_format = tk.StringVar(value="webp")
        
        # 添加压缩模式变量，默认改为无损
        self.compression_mode = tk.StringVar(value="lossless")
        
        self.create_widgets()
        
    def set_window_icon(self):
        """设置窗口图标"""
        try:
            # 尝试加载图标文件（如果存在）
            if getattr(sys, 'frozen', False):
                # 如果是打包后的exe文件，从exe所在目录查找图标
                application_path = os.path.dirname(sys.executable)
                # 对于PyInstaller打包的应用，数据文件在_MEIPASS目录中
                base_path = sys._MEIPASS
            else:
                # 如果是Python脚本，从脚本所在目录查找图标
                application_path = os.path.dirname(os.path.abspath(__file__))
                base_path = application_path
                
            icon_path = os.path.join(base_path, 'icon.ico')
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
            else:
                # 如果找不到icon.ico，尝试使用其他可能的图标文件名
                possible_icons = ['icon.ico', 'favicon.ico', 'app.ico']
                for icon_name in possible_icons:
                    icon_path = os.path.join(base_path, icon_name)
                    if os.path.exists(icon_path):
                        self.root.iconbitmap(icon_path)
                        break
        except Exception as e:
            # 如果设置图标失败，创建一个默认的空图标以确保窗口有图标
            try:
                # 创建一个空的图标（透明的16x16图标）
                icon = tk.PhotoImage(width=16, height=16)
                self.root.iconphoto(True, icon)
            except:
                # 如果所有方法都失败，就使用默认图标
                pass

    def set_initial_window_size(self):
        """设置初始窗口大小"""
        # 固定窗口大小，更符合现代软件设计
        window_width = 1000
        window_height = 700
        
        # 获取屏幕分辨率并居中显示
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        self.root.geometry(f"{window_width}x{window_height}+{x}+{y}")
        self.root.resizable(True, True)

    def setup_modern_theme(self):
        """设置现代化深色主题"""
        # 现代化深色主题配色
        self.bg_color = '#1e1e1e'          # 主背景色
        self.fg_color = '#ffffff'          # 主前景色
        self.accent_color = '#0078d4'      # 强调色（蓝色）
        self.accent_hover = '#0066b4'      # 强调色悬停
        self.secondary_bg = '#2d2d30'      # 次要背景色
        self.tertiary_bg = '#333337'       # 第三背景色
        self.border_color = '#3f3f46'      # 边框颜色
        self.success_color = '#4ec9b0'     # 成功颜色
        self.warning_color = '#dcdcaa'     # 警告颜色
        self.error_color = '#f48771'       # 错误颜色
        
        # 应用背景色
        self.root.configure(bg=self.bg_color)
        
    def create_widgets(self):
        # 设置样式
        style = ttk.Style()
        style.theme_use('clam')
        
        # 配置 ttk 样式
        style.configure('TFrame', background=self.bg_color)
        style.configure('TLabel', background=self.bg_color, foreground=self.fg_color)
        style.configure('Title.TLabel', 
                       background=self.bg_color, 
                       foreground=self.accent_color, 
                       font=("Segoe UI", 16, "bold"))
        style.configure('Status.TLabel', 
                       background=self.bg_color, 
                       foreground='#aaaaaa', 
                       font=("Segoe UI", 10))
        style.configure('Header.TLabel', 
                       background=self.secondary_bg, 
                       foreground=self.fg_color, 
                       font=("Segoe UI", 11, "bold"))
        style.configure('TButton',
                       background=self.accent_color,
                       foreground=self.fg_color,
                       font=("Segoe UI", 10),
                       borderwidth=0,
                       padding=6)
        style.map('TButton',
                 background=[('active', self.accent_hover)],
                 foreground=[('active', self.fg_color)])
        style.configure('Action.TButton',
                       background=self.tertiary_bg,
                       foreground=self.fg_color,
                       font=("Segoe UI", 9),
                       borderwidth=0,
                       padding=5)
        style.map('Action.TButton',
                 background=[('active', self.accent_color)],
                 foreground=[('active', self.fg_color)])
        style.configure("Treeview",
                       background=self.secondary_bg,
                       foreground=self.fg_color,
                       fieldbackground=self.secondary_bg,
                       borderwidth=0,
                       rowheight=30)
        style.configure("Treeview.Heading",
                       background=self.tertiary_bg,
                       foreground=self.fg_color,
                       borderwidth=0,
                       font=("Segoe UI", 9, "bold"))
        style.map("Treeview",
                 background=[('selected', self.accent_color)],
                 foreground=[('selected', self.fg_color)])
        style.configure("TProgressbar",
                       background=self.accent_color,
                       troughcolor=self.tertiary_bg,
                       borderwidth=0)
        style.configure("Horizontal.TScale",
                       background=self.bg_color,
                       troughcolor=self.tertiary_bg)
        # 配置单选按钮样式
        style.configure("TRadiobutton",
                       background=self.bg_color,
                       foreground=self.fg_color,
                       font=("Segoe UI", 10))

        # 标题
        self.title_label = ttk.Label(self.root, text="WebP/AVIF 图片转换器", style='Title.TLabel')
        self.title_label.pack(pady=(20, 10), padx=20, anchor=tk.W)
        
        # 状态标签
        self.status_label = ttk.Label(self.root, 
                                     text="请选择要转换的图片文件或文件夹,支持*.jpg *.jpeg *.png *.bmp *.gif *.tiff *.tif *.ico",
                                     style='Status.TLabel')
        self.status_label.pack(pady=(0, 15), padx=20, anchor=tk.W)
        
        # 按钮框架
        self.button_frame = ttk.Frame(self.root)
        self.button_frame.pack(pady=(0, 15), padx=20, fill=tk.X)
        
        # 选择文件按钮
        self.select_files_btn = ttk.Button(self.button_frame, 
                                          text="选择图片文件", 
                                          command=self.select_files,
                                          style='TButton')
        self.select_files_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        # 选择文件夹按钮
        self.select_folder_btn = ttk.Button(self.button_frame, 
                                           text="选择文件夹", 
                                           command=self.select_folder,
                                           style='TButton')
        self.select_folder_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        # 清空列表按钮
        self.clear_list_btn = ttk.Button(self.button_frame, 
                                        text="清空列表", 
                                        command=self.clear_list,
                                        style='Action.TButton')
        self.clear_list_btn.pack(side=tk.LEFT, padx=(0, 10))
        
        # 文件列表框框架
        self.file_list_frame = ttk.Frame(self.root)
        self.file_list_frame.pack(pady=(0, 15), padx=20, fill=tk.BOTH, expand=True)
        
        # 文件列表标题
        self.file_list_label = ttk.Label(self.file_list_frame, 
                                        text="待转换文件列表:", 
                                        style='Header.TLabel')
        self.file_list_label.pack(anchor=tk.W, pady=(0, 5))
        
        # 创建一个容器框架来正确布局Treeview和滚动条
        tree_container = ttk.Frame(self.file_list_frame)
        tree_container.pack(fill=tk.BOTH, expand=True)
        
        # 文件列表Treeview
        columns = ('source_path', 'source_size', 'target_path', 'target_size')
        self.file_listbox = ttk.Treeview(tree_container, 
                                        columns=columns, 
                                        show='headings', 
                                        height=12)
        
        # 定义表头
        self.file_listbox.heading('source_path', text='源文件路径')
        self.file_listbox.heading('source_size', text='源文件大小')
        self.file_listbox.heading('target_path', text='目标文件路径')
        self.file_listbox.heading('target_size', text='目标文件大小')
        
        # 设置列宽
        self.file_listbox.column('source_path', width=350)
        self.file_listbox.column('source_size', width=100, anchor=tk.CENTER)
        self.file_listbox.column('target_path', width=350)
        self.file_listbox.column('target_size', width=100, anchor=tk.CENTER)
        
        # 添加滚动条
        scrollbar_y = ttk.Scrollbar(tree_container, orient=tk.VERTICAL, command=self.file_listbox.yview)
        scrollbar_x = ttk.Scrollbar(tree_container, orient=tk.HORIZONTAL, command=self.file_listbox.xview)
        self.file_listbox.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
        
        # 布局 - 先放置滚动条，再放置Treeview
        self.file_listbox.grid(row=0, column=0, sticky='nsew')
        scrollbar_y.grid(row=0, column=1, sticky='ns')
        scrollbar_x.grid(row=1, column=0, sticky='ew')
        
        # 配置grid权重以允许扩展
        tree_container.grid_rowconfigure(0, weight=1)
        tree_container.grid_columnconfigure(0, weight=1)
        
        # 底部框架
        self.bottom_frame = ttk.Frame(self.root)
        self.bottom_frame.pack(pady=(0, 20), padx=20, fill=tk.X)
        
        # 质量设置框架
        self.quality_frame = ttk.Frame(self.bottom_frame)
        self.quality_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)
        
        # 质量标签
        self.quality_label = ttk.Label(self.quality_frame, 
                                      text="转换质量:", 
                                      style='Status.TLabel')
        self.quality_label.pack(anchor=tk.W)
        
        # 质量滑块
        self.quality_var = tk.IntVar(value=80)
        self.quality_scale = ttk.Scale(self.quality_frame, 
                                      from_=1, 
                                      to=100, 
                                      orient=tk.HORIZONTAL,
                                      variable=self.quality_var,
                                      length=200)
        self.quality_scale.pack(side=tk.LEFT, pady=(5, 0))
        
        # 质量值显示
        self.quality_value_label = ttk.Label(self.quality_frame, 
                                            text=f"{self.quality_var.get()}%", 
                                            style='Status.TLabel',
                                            width=5)
        self.quality_value_label.pack(side=tk.LEFT, padx=(10, 0))
        
        # 绑定质量滑块变化事件
        self.quality_scale.configure(command=self.on_quality_change)
        
        # 压缩模式框架
        self.mode_frame = ttk.Frame(self.bottom_frame)
        self.mode_frame.pack(side=tk.LEFT, padx=(20, 0))

        # 压缩模式标签
        self.mode_label = ttk.Label(self.mode_frame, 
                                   text="压缩模式:", 
                                   style='Status.TLabel')
        self.mode_label.pack(anchor=tk.CENTER)

        # 压缩模式选择按钮
        self.mode_frame_inner = ttk.Frame(self.mode_frame)
        self.mode_frame_inner.pack(pady=(5, 0))

        self.lossy_radio = ttk.Radiobutton(self.mode_frame_inner, 
                                          text="有损", 
                                          variable=self.compression_mode, 
                                          value="lossy",
                                          style="TRadiobutton")
        self.lossy_radio.pack(side=tk.LEFT)

        self.lossless_radio = ttk.Radiobutton(self.mode_frame_inner, 
                                             text="无损", 
                                             variable=self.compression_mode, 
                                             value="lossless",
                                             style="TRadiobutton")
        self.lossless_radio.pack(side=tk.LEFT, padx=(10, 0))
        
        # 格式选择框架
        self.format_frame = ttk.Frame(self.bottom_frame)
        self.format_frame.pack(side=tk.LEFT, padx=(20, 0))

        # 格式标签
        self.format_label = ttk.Label(self.format_frame, 
                                     text="输出格式:", 
                                     style='Status.TLabel')
        self.format_label.pack(anchor=tk.CENTER)

        # 格式选择按钮
        self.format_frame_inner = ttk.Frame(self.format_frame)
        self.format_frame_inner.pack(pady=(5, 0))

        self.webp_radio = ttk.Radiobutton(self.format_frame_inner, 
                                         text="WebP", 
                                         variable=self.output_format, 
                                         value="webp",
                                         style="TRadiobutton")
        self.webp_radio.pack(side=tk.LEFT)

        self.avif_radio = ttk.Radiobutton(self.format_frame_inner, 
                                         text="AVIF", 
                                         variable=self.output_format, 
                                         value="avif",
                                         style="TRadiobutton")
        self.avif_radio.pack(side=tk.LEFT, padx=(10, 0))
        
        # 转换按钮框架
        self.convert_frame = ttk.Frame(self.bottom_frame)
        self.convert_frame.pack(side=tk.RIGHT)
        
        # 转换按钮
        self.convert_btn = ttk.Button(self.convert_frame, 
                                     text="一键转换", 
                                     command=self.convert_images,
                                     style='TButton')
        self.convert_btn.pack()
        
        # 进度条
        self.progress = ttk.Progressbar(self.convert_frame, 
                                       orient=tk.HORIZONTAL, 
                                       length=200, 
                                       mode='determinate')
        self.progress.pack(pady=(10, 0))
        
    def on_quality_change(self, value):
        """当质量滑块变化时更新显示"""
        quality = int(float(value))
        self.quality_value_label.configure(text=f"{quality}%")
        
        # 重新计算所有文件的预估文件大小
        if self.file_listbox.get_children():
            for item in self.file_listbox.get_children():
                values = self.file_listbox.item(item, 'values')
                source_path = values[0]
                if os.path.exists(source_path):
                    try:
                        # 预估大小为原图大小的一定比例
                        quality_ratio = quality / 100.0
                        estimated_size = os.path.getsize(source_path) * quality_ratio * 0.8
                        size_str = self.format_file_size(estimated_size)
                        # 更新显示
                        new_values = (values[0], values[1], values[2], size_str)
                        self.file_listbox.item(item, values=new_values)
                    except Exception:
                        pass
                        
    def format_file_size(self, size_bytes):
        """格式化文件大小显示"""
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.1f} KB"
        elif size_bytes < 1024 * 1024 * 1024:
            return f"{size_bytes / (1024 * 1024):.1f} MB"
        else:
            return f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"
            
    def select_files(self):
        filetypes = (
            ("Image files", "*.jpg *.jpeg *.png *.bmp *.gif *.tiff *.tif *.ico"),
            ("JPEG files", "*.jpg *.jpeg"),
            ("PNG files", "*.png"),
            ("BMP files", "*.bmp"),
            ("GIF files", "*.gif"),
            ("TIFF files", "*.tiff *.tif"),
            ("ICO files", "*.ico"),
            ("All files", "*.*")
        )
        
        filenames = filedialog.askopenfilenames(title="选择图片文件", filetypes=filetypes)
        
        for filename in filenames:
            # 跳过已选择的输出格式文件，避免重复转换
            if not (filename.lower().endswith('.webp') or filename.lower().endswith('.avif')):
                # 检查是否已存在
                exists = False
                for item in self.file_listbox.get_children():
                    if self.file_listbox.item(item, 'values')[0] == filename:
                        exists = True
                        break
                        
                if not exists:
                    # 获取文件大小
                    file_size = os.path.getsize(filename)
                    size_str = self.format_file_size(file_size)
                    
                    # 生成目标文件路径
                    exe_dir = self.get_executable_dir()
                    output_dir = os.path.join(exe_dir, f"{self.output_format.get()}s")
                    base_name = os.path.splitext(os.path.basename(filename))[0]
                    target_path = os.path.join(output_dir, base_name + f".{self.output_format.get()}")
                    
                    # 预估大小
                    quality_ratio = self.quality_var.get() / 100.0
                    estimated_size = file_size * quality_ratio * 0.8
                    target_size_str = self.format_file_size(estimated_size)
                    
                    # 添加到列表
                    self.file_listbox.insert('', tk.END, values=(filename, size_str, target_path, target_size_str))
        
        self.update_status()

    def select_folder(self):
        folder_path = filedialog.askdirectory(title="选择包含图片的文件夹")
        
        if folder_path:
            # 扩展支持更多图片格式，但排除webp和avif格式
            image_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff', '.tif', '.ico')
            files_added = 0
            
            for root, dirs, files in os.walk(folder_path):
                for file in files:
                    if file.lower().endswith(image_extensions):
                        full_path = os.path.join(root, file)
                        # 检查是否已存在
                        exists = False
                        for item in self.file_listbox.get_children():
                            if self.file_listbox.item(item, 'values')[0] == full_path:
                                exists = True
                                break
                                
                        if not exists:
                            # 获取文件大小
                            file_size = os.path.getsize(full_path)
                            size_str = self.format_file_size(file_size)
                            
                            # 生成目标文件路径
                            exe_dir = self.get_executable_dir()
                            output_dir = os.path.join(exe_dir, f"{self.output_format.get()}s")
                            base_name = os.path.splitext(os.path.basename(full_path))[0]
                            target_path = os.path.join(output_dir, base_name + f".{self.output_format.get()}")
                            
                            # 预估大小
                            quality_ratio = self.quality_var.get() / 100.0
                            estimated_size = file_size * quality_ratio * 0.8
                            target_size_str = self.format_file_size(estimated_size)
                            
                            # 添加到列表
                            self.file_listbox.insert('', tk.END, values=(full_path, size_str, target_path, target_size_str))
                            files_added += 1
            
            self.update_status()
            messagebox.showinfo("文件夹选择", f"从文件夹中添加了 {files_added} 个图片文件")

    def clear_list(self):
        for item in self.file_listbox.get_children():
            self.file_listbox.delete(item)
        self.update_status()
        
    def update_status(self):
        count = len(self.file_listbox.get_children())
        format_name = "WebP" if self.output_format.get() == "webp" else "AVIF"
        self.status_label.config(text=f"共 {count} 个文件待转换为{format_name}格式")

        
    def get_executable_dir(self):
        """获取可执行文件所在目录"""
        if getattr(sys, 'frozen', False):
            # 如果是打包后的exe文件
            return os.path.dirname(sys.executable)
        else:
            # 如果是Python脚本
            return os.path.dirname(os.path.abspath(__file__))
        
    def convert_images(self):
        files = []
        for item in self.file_listbox.get_children():
            values = self.file_listbox.item(item, 'values')
            files.append((values[0], values[2]))  # (源路径, 目标路径)
            
        if not files:
            messagebox.showwarning("转换失败", "请先选择要转换的图片文件")
            return
            
        # 获取质量和输出格式
        quality = self.quality_var.get()
        format = self.output_format.get()
        compression = self.compression_mode.get()
        
        # 检查Pillow版本是否支持AVIF
        if format == "avif":
            from PIL import __version__ as pillow_version
            version_parts = [int(x) for x in pillow_version.split(".")]
            if version_parts[0] < 9:
                messagebox.showwarning("AVIF支持警告", 
                                      f"检测到Pillow版本 {pillow_version}\n"
                                      "AVIF格式需要Pillow 9.0.0或更高版本\n"
                                      "建议升级: pip install --upgrade Pillow\n"
                                      "将继续尝试转换...")
        
        # 设置进度条
        self.progress['maximum'] = len(files)
        self.progress['value'] = 0
        
        success_count = 0
        fail_count = 0
        
        # 获取程序执行目录并创建对应子目录
        exe_dir = self.get_executable_dir()
        output_dir = os.path.join(exe_dir, f"{format}s")
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
        
        for i, (source_path, target_path) in enumerate(files):
            # 跳过输出格式文件，避免重复转换
            if source_path.lower().endswith(f'.{format}'):
                fail_count += 1
                self.progress['value'] = i + 1
                self.root.update_idletasks()
                continue
                
            try:
                # 加载图片
                img = Image.open(source_path)
                
                # 处理RGBA模式的图片 (PNG透明图)
                if img.mode == "RGBA":
                    # 创建白色背景
                    background = Image.new("RGB", img.size, (255, 255, 255))
                    background.paste(img, mask=img.split()[3])  # 使用alpha通道作为mask
                    img = background
                elif img.mode != "RGB":
                    img = img.convert("RGB")
                
                # 保存为指定格式
                if format == "webp":
                    if compression == "lossless":
                        img.save(target_path, "webp", lossless=True)
                    else:
                        img.save(target_path, "webp", quality=quality)
                elif format == "avif":
                    # AVIF格式保存，需要Pillow 9.0.0+版本支持
                    try:
                        if compression == "lossless":
                            img.save(target_path, "avif", quality=100, lossless=True)
                        else:
                            img.save(target_path, "avif", quality=quality)
                    except Exception as e:
                        # 如果AVIF保存失败，检查错误类型
                        error_msg = str(e).lower()
                        if "avif" in error_msg or "unknown" in error_msg or "format" in error_msg:
                            # AVIF格式不支持，提示用户并回退到WebP格式
                            messagebox.showwarning("AVIF格式不支持", 
                                                  "当前环境不支持AVIF格式转换。\n"
                                                  "已自动回退到WebP格式。\n"
                                                  "如需使用AVIF，请确保：\n"
                                                  "1. Pillow版本 >= 9.0.0\n"
                                                  "2. 安装了支持AVIF的编解码器")
                            # 回退到WebP格式
                            target_path = target_path.replace(".avif", ".webp")
                            if compression == "lossless":
                                img.save(target_path, "webp", lossless=True)
                            else:
                                img.save(target_path, "webp", quality=quality)
                            # 更新列表中的目标路径
                            item_id = self.file_listbox.get_children()[i]
                            values = self.file_listbox.item(item_id, 'values')
                            new_values = (values[0], values[1], target_path, values[3])
                            self.file_listbox.item(item_id, values=new_values)
                        else:
                            raise e  # 其他错误重新抛出
                
                # 更新实际文件大小
                if os.path.exists(target_path):
                    actual_size = os.path.getsize(target_path)
                    size_str = self.format_file_size(actual_size)
                    # 更新列表中的实际大小
                    item_id = self.file_listbox.get_children()[i]
                    values = self.file_listbox.item(item_id, 'values')
                    new_values = (values[0], values[1], values[2], size_str)
                    self.file_listbox.item(item_id, values=new_values)
                
                success_count += 1
                
            except Exception as e:
                print(f"转换失败 {source_path}: {str(e)}")
                fail_count += 1
                
            # 更新进度条
            self.progress['value'] = i + 1
            self.root.update_idletasks()
            
        # 转换完成
        self.progress['value'] = 0
        format_name = "WebP" if format == "webp" else "AVIF"
        compression_name = "无损" if compression == "lossless" else "有损"
        messagebox.showinfo("转换完成", f"{format_name}格式{compression_name}转换完成!\n成功: {success_count} 个文件\n失败: {fail_count} 个文件")
        
        # 清空列表
        self.clear_list()

# 添加编译说明和使用PyInstaller的示例命令
"""
编译成可执行文件的方法:

1. 安装PyInstaller:
   pip install pyinstaller

2. 编译命令:
   pyinstaller --add-data="icon.ico;." --icon=icon.ico --name=WebPConverter --noconfirm --onefile --windowed "main.py"
   pyinstaller --add-data="icon.ico;." --icon=icon.ico --name=WebPConverter --noconfirm --onedir --windowed "main.py"

   参数说明:
   --add-data="源路径;目标路径": 添加数据文件到可执行文件中
      - Windows系统使用分号(;)分隔源路径和目标路径
      - Linux/Mac系统使用冒号(:)分隔源路径和目标路径
      - 示例: --add-data="icon.ico;." 表示将icon.ico文件添加到可执行文件根目录
   --noconfirm: 不询问覆盖已存在的文件
   --onefile: 打包成单个exe文件
   --onedir: 打包成多文件目录格式
   --windowed: Windows系统禁用命令行窗口

3. 更多选项:
   --icon=icon.ico: 指定exe图标
   --name=WebPConverter: 指定生成的exe文件名
   --add-data="resources;resources": 添加额外资源文件目录

4. 编译后的文件位置:
   编译完成后会在当前目录生成dist文件夹，其中包含可执行文件

5. 注意事项:
   - 使用--add-data添加的文件，在程序中需要使用sys._MEIPASS获取实际路径
   - 示例代码获取资源文件路径:
     if getattr(sys, 'frozen', False):
         # 打包后路径
         base_path = sys._MEIPASS
     else:
         # 开发时路径
         base_path = os.path.abspath(".")
     icon_path = os.path.join(base_path, "icon.ico")
     
   - 在set_window_icon方法中已经实现了正确的资源路径获取逻辑，可以正常加载打包进exe的图标文件
   
   - 打包时确保icon.ico文件与main.py在同一目录下
   - 可以通过以下命令验证打包是否成功:
     pyinstaller --add-data="icon.ico;." --icon=icon.ico --windowed --onefile main.py
"""
if __name__ == "__main__":
    root = tk.Tk()
    root.withdraw()  # 先隐藏窗口
    app = ImageConverterApp(root)
    root.deiconify()  # 初始化完成后再显示窗口
    root.mainloop()